Created
October 9, 2018 11:50
-
-
Save bartosz25/d0f9c4fb852a63e75f446a51dccb65e3 to your computer and use it in GitHub Desktop.
Apache Cassandra wide rows vs skinny rows micro-benchmark
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.waitingforcode; | |
import com.datastax.driver.core.Cluster; | |
import com.datastax.driver.core.Session; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.stream.Collectors; | |
public class CassandraSession { | |
private static final String TEST_KEYSPACE = "test_keyspace"+System.currentTimeMillis(); | |
private final Session session; | |
private final List<String> wideRowTable80Columns = new ArrayList<>(); | |
private final List<String> wideRowTable40Columns = new ArrayList<>(); | |
private final List<String> wideRowTable20Columns = new ArrayList<>(); | |
public CassandraSession() { | |
Cluster cluster = Cluster.builder().addContactPoint("127.0.0.1").build(); | |
session = cluster.connect(); | |
for (int i = 0; i < 80; i++) { | |
String columnName = "column"+i; | |
wideRowTable80Columns.add(columnName); | |
if (i < 40) { | |
wideRowTable40Columns.add(columnName); | |
if (i < 20) { | |
wideRowTable20Columns.add(columnName); | |
} | |
} | |
} | |
session.execute("CREATE KEYSPACE IF NOT EXISTS "+ TEST_KEYSPACE +" WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 2}"); | |
session.execute("USE "+ TEST_KEYSPACE); | |
} | |
public List<String> getWideRowTable80Columns() { | |
return wideRowTable80Columns; | |
} | |
public List<String> getWideRowTable40Columns() { | |
return wideRowTable40Columns; | |
} | |
public List<String> getWideRowTable20Columns() { | |
return wideRowTable20Columns; | |
} | |
public void execute(String query) { | |
session.execute(query); | |
} | |
public void createTables() { | |
session.execute(getWideRowTableCreationQuery(wideRowTable80Columns)); | |
session.execute(getWideRowTableCreationQuery(wideRowTable40Columns)); | |
session.execute(getWideRowTableCreationQuery(wideRowTable20Columns)); | |
String skinnyRowTableQuery = "CREATE TABLE skinny_row_test ( col text, value text, PRIMARY KEY (col)) "; | |
session.execute(skinnyRowTableQuery); | |
} | |
private String getWideRowTableCreationQuery(List<String> columns) { | |
int columnsCount = columns.size(); | |
String wideRowTableQuery = "CREATE TABLE wide_rows_test_"+columnsCount+" (id INT, "; | |
String wideRowTableCols = columns.stream().map(column -> column+" text ") | |
.collect(Collectors.joining(",")); | |
wideRowTableQuery += wideRowTableCols; | |
wideRowTableQuery += " , PRIMARY KEY(id) )"; | |
return wideRowTableQuery; | |
} | |
public void closeSession() { | |
session.close(); | |
session.getCluster().close(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>com.waitingforcode</groupId> | |
<artifactId>wide-rows</artifactId> | |
<version>1.0-SNAPSHOT</version> | |
<name>wide-rows</name> | |
<properties> | |
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | |
<maven.compiler.source>1.8</maven.compiler.source> | |
<maven.compiler.target>1.8</maven.compiler.target> | |
</properties> | |
<dependencies> | |
<dependency> | |
<groupId>org.openjdk.jmh</groupId> | |
<artifactId>jmh-core</artifactId> | |
<version>1.21</version> | |
</dependency> | |
<dependency> | |
<groupId>org.openjdk.jmh</groupId> | |
<artifactId>jmh-generator-annprocess</artifactId> | |
<version>1.21</version> | |
</dependency> | |
<dependency> | |
<groupId>com.datastax.cassandra</groupId> | |
<artifactId>cassandra-driver-core</artifactId> | |
<version>3.6.0</version> | |
</dependency> | |
<dependency> | |
<groupId>com.datastax.cassandra</groupId> | |
<artifactId>cassandra-driver-mapping</artifactId> | |
<version>3.6.0</version> | |
</dependency> | |
<dependency> | |
<groupId>org.apache.cassandra</groupId> | |
<artifactId>cassandra-all</artifactId> | |
<version>3.11.3</version> | |
</dependency> | |
<dependency> | |
<groupId>junit</groupId> | |
<artifactId>junit</artifactId> | |
<version>4.11</version> | |
<scope>test</scope> | |
</dependency> | |
</dependencies> | |
<build> | |
<pluginManagement> | |
<plugins> | |
<plugin> | |
<artifactId>maven-clean-plugin</artifactId> | |
<version>3.0.0</version> | |
</plugin> | |
<plugin> | |
<artifactId>maven-resources-plugin</artifactId> | |
<version>3.0.2</version> | |
</plugin> | |
<plugin> | |
<artifactId>maven-compiler-plugin</artifactId> | |
<version>3.7.0</version> | |
</plugin> | |
<plugin> | |
<artifactId>maven-surefire-plugin</artifactId> | |
<version>2.20.1</version> | |
</plugin> | |
<plugin> | |
<artifactId>maven-jar-plugin</artifactId> | |
<version>3.0.2</version> | |
</plugin> | |
<plugin> | |
<artifactId>maven-install-plugin</artifactId> | |
<version>2.5.2</version> | |
</plugin> | |
<plugin> | |
<artifactId>maven-deploy-plugin</artifactId> | |
<version>2.8.2</version> | |
</plugin> | |
</plugins> | |
</pluginManagement> | |
</build> | |
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.waitingforcode; | |
import org.openjdk.jmh.annotations.*; | |
import java.util.List; | |
import java.util.concurrent.TimeUnit; | |
import java.util.stream.Collectors; | |
@OutputTimeUnit(TimeUnit.MILLISECONDS) | |
@BenchmarkMode(Mode.All) | |
public class ReadMicroBenchmark { | |
@State(Scope.Thread) | |
public static class InitializationState { | |
private CassandraSession cassandraSession = new CassandraSession(); | |
{ | |
String colsToInsertInto80ColsTable = getColumnsToInsertClause(cassandraSession.getWideRowTable80Columns()); | |
String valuesToInsert80ColsTable = getValuesToInsertClause(cassandraSession.getWideRowTable80Columns()); | |
String colsToInsertInto40ColsTable = getColumnsToInsertClause(cassandraSession.getWideRowTable40Columns()); | |
String valuesToInsert40ColsTable = getValuesToInsertClause(cassandraSession.getWideRowTable40Columns()); | |
String colsToInsertInto20ColsTable = getColumnsToInsertClause(cassandraSession.getWideRowTable20Columns()); | |
String valuesToInsert20ColsTable = getValuesToInsertClause(cassandraSession.getWideRowTable20Columns()); | |
cassandraSession.createTables(); | |
for (int i = 0; i < ROWS_TO_INSERT; i++) { | |
cassandraSession.execute("INSERT INTO wide_rows_test_80 (id, "+colsToInsertInto80ColsTable+") VALUES (" + | |
i+", "+valuesToInsert80ColsTable+")"); | |
cassandraSession.execute("INSERT INTO wide_rows_test_40 (id, "+colsToInsertInto40ColsTable+") VALUES (" + | |
i+", "+valuesToInsert40ColsTable+")"); | |
cassandraSession.execute("INSERT INTO wide_rows_test_20 (id, "+colsToInsertInto20ColsTable+") VALUES (" + | |
i+", "+valuesToInsert20ColsTable+")"); | |
for (int j = 0; j < cassandraSession.getWideRowTable80Columns().size(); j++) { | |
String key = i+"_"+cassandraSession.getWideRowTable80Columns().get(j); | |
cassandraSession.execute("INSERT INTO skinny_row_test (col, value) VALUES ('"+key+"', 'value"+i+"')"); | |
} | |
} | |
} | |
private static final int ROWS_TO_INSERT = 100; | |
private static String getColumnsToInsertClause(List<String> columns) { | |
return columns.stream().collect(Collectors.joining(",")); | |
} | |
private static String getValuesToInsertClause(List<String> columns) { | |
return columns.stream() | |
.map(colName -> "'"+colName + " value'") | |
.collect(Collectors.joining(",")); | |
} | |
@Setup(Level.Trial) | |
public void doSetup() { | |
} | |
@TearDown(Level.Trial) | |
public void doTearDown() { | |
cassandraSession.closeSession(); | |
} | |
} | |
@Benchmark | |
public void read_all_wide_rows_80_cols(InitializationState initializationState) { | |
for (int i = 0; i < initializationState.ROWS_TO_INSERT; i++) { | |
initializationState.cassandraSession.execute("SELECT * FROM wide_rows_test_80 WHERE id = "+i); | |
} | |
} | |
@Benchmark | |
public void read_all_wide_rows_40_cols(InitializationState initializationState) { | |
for (int i = 0; i < initializationState.ROWS_TO_INSERT; i++) { | |
initializationState.cassandraSession.execute("SELECT * FROM wide_rows_test_40 WHERE id = "+i); | |
} | |
} | |
@Benchmark | |
public void read_all_wide_rows_20_cols(InitializationState initializationState) { | |
for (int i = 0; i < initializationState.ROWS_TO_INSERT; i++) { | |
initializationState.cassandraSession.execute("SELECT * FROM wide_rows_test_20 WHERE id = "+i); | |
} | |
} | |
@Benchmark | |
public void read_all_skinny_rows(InitializationState initializationState) { | |
for (int i = 0; i < initializationState.ROWS_TO_INSERT; i++) { | |
for (int j = 0; j < initializationState.cassandraSession.getWideRowTable80Columns().size(); j++) { | |
String key = i+"_"+initializationState.cassandraSession.getWideRowTable80Columns().get(j); | |
initializationState.cassandraSession.execute("SELECT * FROM skinny_row_test WHERE col = '"+key+"'"); | |
} | |
} | |
} | |
@Benchmark | |
public void read_20_columns_from_all_wide_row_80_cols_table(InitializationState initializationState) { | |
for (int i = 0; i < initializationState.ROWS_TO_INSERT; i++) { | |
initializationState.cassandraSession.execute("SELECT id, column0, column1, column2, column3, column4, column5, column6, column7, column8," + | |
"column9, column10, column11, column12, column13, column14, column15, column16, column17, " + | |
"column18, column19 FROM wide_rows_test_80 WHERE id = "+i); | |
} | |
} | |
@Benchmark | |
public void read_20_columns_from_all_wide_row_40_cols_table(InitializationState initializationState) { | |
for (int i = 0; i < initializationState.ROWS_TO_INSERT; i++) { | |
initializationState.cassandraSession.execute("SELECT id, column0, column1, column2, column3, column4, column5, column6, column7, column8," + | |
"column9, column10, column11, column12, column13, column14, column15, column16, column17, " + | |
"column18, column19 FROM wide_rows_test_40 WHERE id = "+i); | |
} | |
} | |
@Benchmark | |
public void read_20_columns_from_all_wide_row_20_cols_table(InitializationState initializationState) { | |
for (int i = 0; i < initializationState.ROWS_TO_INSERT; i++) { | |
initializationState.cassandraSession.execute("SELECT id, column0, column1, column2, column3, column4, column5, column6, column7, column8," + | |
"column9, column10, column11, column12, column13, column14, column15, column16, column17, " + | |
"column18, column19 FROM wide_rows_test_20 WHERE id = "+i); | |
} | |
} | |
@Benchmark | |
public void read_20_rows_from_all_skinny_rows(InitializationState initializationState) { | |
for (int i = 0; i < initializationState.ROWS_TO_INSERT; i++) { | |
for (int j = 0; j < 20; j++) { | |
String key = i+"_"+initializationState.cassandraSession.getWideRowTable80Columns().get(j); | |
initializationState.cassandraSession.execute("SELECT * FROM skinny_row_test WHERE col = '"+key+"'"); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.waitingforcode; | |
import org.openjdk.jmh.runner.Runner; | |
import org.openjdk.jmh.runner.RunnerException; | |
import org.openjdk.jmh.runner.options.Options; | |
import org.openjdk.jmh.runner.options.OptionsBuilder; | |
public class ReadMicroBenchmarkRunner { | |
public static void main(String[] args) throws RunnerException { | |
Options opt = new OptionsBuilder() | |
.include(ReadMicroBenchmark.class.getSimpleName()) | |
.forks(1) | |
.threads(1) | |
.warmupIterations(0) | |
.measurementIterations(3) | |
.output("read_benchmark_debug.txt") | |
.result("read_benchmark_results.txt") | |
.build(); | |
new Runner(opt).run(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.waitingforcode; | |
import org.openjdk.jmh.annotations.*; | |
import java.util.List; | |
import java.util.concurrent.TimeUnit; | |
import java.util.stream.Collectors; | |
@OutputTimeUnit(TimeUnit.MILLISECONDS) | |
@BenchmarkMode(Mode.All) | |
public class WriteMicroBenchmark { | |
@State(Scope.Thread) | |
public static class InitializationState { | |
private CassandraSession cassandraSession = new CassandraSession(); | |
private String colsToInsertInto80 = getColsToInertClause(cassandraSession.getWideRowTable80Columns()); | |
private String valuesToInsertInto80 = getValuesToInsertClause(cassandraSession.getWideRowTable80Columns()); | |
private String colsToInsertInto40 = getColsToInertClause(cassandraSession.getWideRowTable40Columns()); | |
private String valuesToInsertInto40 = getValuesToInsertClause(cassandraSession.getWideRowTable40Columns()); | |
private String colsToInsertInto20 = getColsToInertClause(cassandraSession.getWideRowTable20Columns()); | |
private String valuesToInsertInto20 = getValuesToInsertClause(cassandraSession.getWideRowTable20Columns()); | |
private static final int ROWS_TO_INSERT = 100; | |
private static String getColsToInertClause(List<String> columns) { | |
return columns.stream().collect(Collectors.joining(",")); | |
} | |
private static String getValuesToInsertClause(List<String> columns) { | |
return columns.stream() | |
.map(colName -> "'"+colName + " value'") | |
.collect(Collectors.joining(",")); | |
} | |
@Setup(Level.Trial) | |
public void doSetup() { | |
cassandraSession.createTables(); | |
} | |
@TearDown(Level.Trial) | |
public void doTearDown() { | |
cassandraSession.closeSession(); | |
} | |
} | |
@Benchmark | |
public void write_wide_rows_to_80_cols_table(InitializationState initializationState) { | |
for (int i = 0; i < initializationState.ROWS_TO_INSERT; i++) { | |
initializationState.cassandraSession.execute("INSERT INTO wide_rows_test_80 (id, "+initializationState.colsToInsertInto80 +") VALUES (" + | |
i+", "+initializationState.valuesToInsertInto80 +")"); | |
} | |
} | |
@Benchmark | |
public void write_wide_rows_to_40_cols_table(InitializationState initializationState) { | |
for (int i = 0; i < initializationState.ROWS_TO_INSERT; i++) { | |
initializationState.cassandraSession.execute("INSERT INTO wide_rows_test_40 (id, "+initializationState.colsToInsertInto40 +") VALUES (" + | |
i+", "+initializationState.valuesToInsertInto40 +")"); | |
} | |
} | |
@Benchmark | |
public void write_wide_rows_to_20_cols_table(InitializationState initializationState) { | |
for (int i = 0; i < initializationState.ROWS_TO_INSERT; i++) { | |
initializationState.cassandraSession.execute("INSERT INTO wide_rows_test_20 (id, "+initializationState.colsToInsertInto20 +") VALUES (" + | |
i+", "+initializationState.valuesToInsertInto20 +")"); | |
} | |
} | |
@Benchmark | |
public void write_skinny_rows(InitializationState initializationState) { | |
for (int i = 0; i < initializationState.ROWS_TO_INSERT; i++) { | |
for (int j = 0; j < initializationState.cassandraSession.getWideRowTable80Columns().size(); j++) { | |
String key = initializationState.cassandraSession.getWideRowTable80Columns().get(j); | |
initializationState.cassandraSession.execute("INSERT INTO skinny_row_test (col, value) VALUES ('"+key+"', 'value "+key+"')"); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.waitingforcode; | |
import org.openjdk.jmh.runner.Runner; | |
import org.openjdk.jmh.runner.RunnerException; | |
import org.openjdk.jmh.runner.options.Options; | |
import org.openjdk.jmh.runner.options.OptionsBuilder; | |
public class WriteMicroBenchmarkRunner { | |
public static void main(String[] args) throws RunnerException { | |
Options opt = new OptionsBuilder() | |
.include(WriteMicroBenchmark.class.getSimpleName()) | |
.forks(1) | |
.threads(1) | |
.warmupIterations(0) | |
.measurementIterations(3) | |
.output("write_benchmark_debug.txt") | |
.result("write_benchmark_results.txt") | |
.build(); | |
new Runner(opt).run(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment